package gsssh

import (
	"errors"
	"fmt"
	"runtime/debug"
	"time"

	"gitee.com/Sxiaobai/gs/v2/gstool"
	"golang.org/x/crypto/ssh"
)

const (
	RunTypeTerminal = iota + 1
	RunTypeBridge
)

type SshConfig struct {
	Name             string `json:"name"` //自定义名称
	Host             string `json:"host"`
	Port             string `json:"port"`
	UserName         string `json:"username"`
	Password         string `json:"password"`
	GsSlog           *gstool.GsSlog
	client           *ssh.Client
	isRunning        bool         //是否已运行
	terminal         *Terminal    //终端
	bridge           Bridge       //桥接
	runTimeoutTicker *time.Ticker //超时的ticker
	RunType          int          //执行类型
	MaxRunSecond     int          //最大执行时间 不超过40秒
	PtyConfig        PtyConfig    //终端配置
}

type PtyConfig struct {
	Term   string `json:"term"   yaml:"term"`   // 终端类型
	Height int    `json:"height" yaml:"height"` // 行数
	Width  int    `json:"width"  yaml:"width"`  // 列数 会影响输出的内容是否换行
	// 把常用的 TerminalModes 单独拆字段，零值即“不设置”
	Echo        uint32 `json:"echo"           yaml:"echo"`       // 把用户敲的命令回显 0 关闭，1 开启
	RawMode     bool   `json:"raw_mode"       yaml:"raw_mode"`   // true 时把 ECHO、ICANON 等全部关掉
	InputSpeed  uint32 `json:"input_speed"  yaml:"input_speed"`  // 波特率
	OutputSpeed uint32 `json:"output_speed" yaml:"output_speed"` // 波特率
}

// NewSshAuthPassword ssh auth password 一个本地端口只允许做一次桥接
func NewSshAuthPassword(host, port, user, password string) *SshConfig {
	return &SshConfig{
		Host:     host,
		Port:     port,
		UserName: user,
		Password: password,
		terminal: &Terminal{
			runStatus: StatusWait,
		},
	}
}

// SetMaxRunSecond 设置最大执行超时时间 不能超过40秒
func (h *SshConfig) SetMaxRunSecond(maxRnuSecond int) {
	if maxRnuSecond > 40 {
		maxRnuSecond = 40
	}
	if maxRnuSecond < 0 {
		maxRnuSecond = 40
	}
	h.MaxRunSecond = maxRnuSecond
}

func (h *SshConfig) SetPtyConfig(ptyConfig PtyConfig) {
	h.PtyConfig = ptyConfig
}

// ConnectAuthPassword ssh auth password
func (h *SshConfig) ConnectAuthPassword() error {
	if h.isRunning {
		return nil
	}
	sshConfig := &ssh.ClientConfig{
		User: h.UserName,
		Auth: []ssh.AuthMethod{
			ssh.Password(h.Password),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(), // In production environments, do not use InsecureIgnoreHostKey
	}
	var sshConnErr error
	h.client, sshConnErr = ssh.Dial("tcp", fmt.Sprintf(`%s:%s`, h.Host, h.Port), sshConfig)
	if sshConnErr != nil {
		h.Errof(`连接失败 %s`, sshConnErr.Error())
		return errors.New(fmt.Sprintf(`ssh conn error：%s`, sshConnErr.Error()))
	}
	//最大执行时间 默认40秒
	if h.MaxRunSecond > 0 {
		h.SetMaxRunSecond(h.MaxRunSecond)
	} else {
		h.SetMaxRunSecond(40)
	}
	h.isRunning = true
	return nil
}

// Close 释放所有资源
func (h *SshConfig) Close() {
	if h.client != nil {
		sshCloseErr := h.client.Close()
		if sshCloseErr != nil {
			//可能会报错 不管
		}
		h.client = nil
	}
	if h.RunType == RunTypeTerminal {
		h.CloseTerminal()
		h.terminal.runStatus = StatusWait
	} else if h.RunType == RunTypeBridge {
		//h.CloseBridge()
	}
	h.isRunning = false
}

func (h *SshConfig) Debugf(msg string, params ...interface{}) {
	if h.GsSlog != nil {
		h.GsSlog.Debugf(gstool.TimeNowUnixToString(`Y-m-d H:i:s`)+` `+msg, params...)
	} else {
		gstool.FmtPrintlnLog(gstool.TimeNowUnixToString(`Y-m-d H:i:s`)+` `+msg, params...)
	}
}

func (h *SshConfig) Errof(msg string, params ...interface{}) {
	if h.GsSlog != nil {
		h.GsSlog.Debugf(gstool.TimeNowUnixToString(`Y-m-d H:i:s`)+` `+msg, params...)
	} else {
		gstool.FmtPrintlnLog(gstool.TimeNowUnixToString(`Y-m-d H:i:s`)+` `+msg, params...)
		debug.PrintStack()
	}
}
